/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.hamacekj.geometr;

import cz.hamacekj.geometr.plugin.InputParametersInterface;
import cz.hamacekj.geometr.plugin.ParameterItem;
import cz.hamacekj.geometr.plugin.ParameterObject;
import cz.hamacekj.geometr.plugin.ParameterString;
import cz.hamacekj.geometr.plugin.ParameterValue;
import cz.hamacekj.geometr.plugin.ValueArgument;
import java.awt.CardLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

/**
 * Třída, která se stará o zobrazení řádky s možností tvorby tohoto
 * constructionObjectu.
 */
public class UIConstructionObject{

    private String name;
    private ImageIcon icon;
    private InputParametersInterface[] params;
    private JPanel panel;
    private CardLayout layout = new CardLayout();
    private Map<String,List<JTextField>> inputs = new HashMap<>();
    private JButton myButton = null;
    private List<ConstructObjectListener> constructionObjectListeners = null;
    
    private JPanel toolbar = null;
    private CardLayout toolbarLayout = null;
    /**
     * Seznam všech zobrazených možností.
     */
    private DefaultComboBoxModel<String> model = null;
    /**
     * Seznam všech dostupných možností.
     */
    private ArrayList<String> options = null;
    /**
     * Pokud je vytvořená jen jediná vstupní možnost, pak neexistuje
     * {@link #model model} ani {@link #options},
     * název možnosti je v tom případě v této proměnné.
     */
    private String singleParamName = null;
    private boolean singleParamShown = false;

    public UIConstructionObject() {
    }

    public UIConstructionObject(String name, ImageIcon icon, InputParametersInterface[] params) {
        this.name = name;
        this.icon = icon;
        this.params = params;
    }
    
    /**
     * Nastaví toolbar ke kterému bude tato třída přidávat svá tlačítka a panely.
     * @param toolbar
     * @param toolbarLayout 
     */
    public void setToolbar(JPanel toolbar, CardLayout toolbarLayout){
        this.toolbar = toolbar;
        this.toolbarLayout = toolbarLayout;
    }
    
    /**
     * Nastaví seznam listenerů, které poslouchají k vytvoření objektů.
     * Zapomene předchozí seznam.
     * @param listeners Seznam listenerů.
     */
    public void setConstructionObjectListeners(List<ConstructObjectListener> listeners){
        this.constructionObjectListeners = listeners;
    }
    
    public void fireConstructionObjectEvent(ConstructObjectEvent ev){
        if(this.constructionObjectListeners == null){
            return;
        }
        for(ConstructObjectListener l : this.constructionObjectListeners){
            l.objectConstructed(ev);
        }
    }

    /**
     * Vrátí tlačítko v hlavním toolbaru, které je asociované s tímto objektem
     * nebo null pokud není nastaveno.
     * @return Tlačítko toolbaru
     */
    public JButton getMyButton(){
        return this.myButton;
    }

    /**
     * Nastaví tlačítko v hlavním toolbaru, které je asociované s tímto objektem.
     * @param myButton Tlačítko toolbaru.
     */
    public void setMyButton(JButton myButton){
        this.myButton = myButton;
    }

    public String getName(){
        return this.name;
    }

    public ImageIcon getIcon(){
        return this.icon;
    }

    /**
     * Zobrazí možnost vytvoření pomocí parametru.
     * @param param Jméno parametru k zobrazení.
     */
    public void showParameter(String param){
        // pokud zobrazeny jediny parametr tohoto jmena tak zobrazit
        if(param.equals(this.singleParamName)){
            this.singleParamShown = true;
            if(this.myButton != null){
                this.myButton.setVisible(true);
            }
            return;
        }
        // pokud tam uz je tak nic nedelej
        if(this.model.getIndexOf(param) != -1){
            return;
        }
        if(this.options.contains(param)){
            this.model.addElement(param);
        }
        if(this.myButton != null){
            this.myButton.setVisible(true);
        }
        this.selectDefault();
    }

    /**
     * Schová možnost vytvoření pomocí parametru param.
     * @param param Jméno parametru ke schování.
     */
    public void hideParameter(String param){
        if(param.equals(this.singleParamName)){
            this.singleParamShown = false;
            if(this.myButton != null){
                this.myButton.setVisible(false);
            }
            return;
        }
        this.model.removeElement(param);
        this.selectDefault();
        if(this.amountParametersShown() == 0 && this.myButton != null){
            this.myButton.setVisible(false);
        }
    }
    
    /**
     * Vybere v seznamu výchozí hodnotu (buď default nebo jedinou jinou).
     */
    public void selectDefault(){
        if(this.amountParametersShown() == 1){
            String d = this.model.getElementAt(1);
            this.model.setSelectedItem(d);
        }else{
            this.model.setSelectedItem("Vyberte");
        }
    }

    /**
     * Vrátí počet zrovna zobrazených typů parametrů.
     * @return počet zrovna zobrazených typů parametrů.
     */
    public int amountParametersShown(){
        if(this.singleParamName == null){
            return this.model.getSize() - 1;
        }
        return this.singleParamShown ? 1 : 0;
    }

    public Container getConstructionPanel(){
        if(panel != null){
            return panel;
        }

        panel = new JPanel(layout);
        if(params.length > 1){
            options = new ArrayList<>(params.length+1);
            options.add("Vyberte");
            for(InputParametersInterface input: params){
                options.add(input.getParametersCaption());
            }
            model = new DefaultComboBoxModel<>(options.toArray(new String[0]));
            JPanel first = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 10));
            panel.add(first, "Vyberte");
            first.add(new JLabel(name, icon, JLabel.LEFT));
            JComboBox<String> comboBox = new JComboBox<>(model);
            comboBox.addActionListener(new ComboBoxSelectedListener(model, layout, panel));
            first.add(comboBox);
            // kazdemu z moznych vstupnich parametru vytvorit vlastni panel cardlayoutu
            for(final InputParametersInterface input: params){
                JPanel itemPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 10));
                itemPanel.add(new JLabel(name, icon, JLabel.LEFT));
                JComboBox<String> comboBox1 = new JComboBox<>(model);
                comboBox1.addActionListener(new ComboBoxSelectedListener(model, layout, panel));
                itemPanel.add(comboBox1);
                final List<JTextField> valueInputs = new ArrayList<>();
                final List<JTextField> objectInputs = new ArrayList<>();
                // za kazdy parametr pridat do soucasneho panelu odpovidajici input
                addParameterInputs(itemPanel, input, valueInputs, objectInputs);
                JButton okButton = new JButton("Ok");
                okButton.addActionListener(new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        submitConstructionObject(input, valueInputs, objectInputs);
                        toolbarLayout.first(toolbar);
                        selectDefault();
                    }
                });
                JButton cancelButton = new JButton("Zpět");
                cancelButton.addActionListener(new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        toolbarLayout.first(toolbar);
                        selectDefault();
                    }
                });
                itemPanel.add(cancelButton);
                itemPanel.add(okButton);
                if(input.getHelp() != null){
                    final String help = input.getHelp();
                    JButton helpButton = new JButton("Nápověda");
                    helpButton.addActionListener(new ActionListener() {

                        @Override
                        public void actionPerformed(ActionEvent e) {
                            HelpDialog d = new HelpDialog();
                            d.setText(help);
                            d.setVisible(true);
                        }
                    });
                    itemPanel.add(helpButton);
                }
                panel.add(itemPanel, input.getParametersCaption());
            }
            return panel;
        }else{
            JPanel first = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 10));
            first.add(new JLabel(name, icon, JLabel.LEFT));
            final InputParametersInterface param = params[0];
            singleParamName = param.getParametersCaption();
            singleParamShown = true;
            final List<JTextField> valueInputs = new ArrayList<>();
            final List<JTextField> objectInputs = new ArrayList<>();
            addParameterInputs(first, param, valueInputs, objectInputs);
            JButton okButton = new JButton("Ok");
            okButton.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    submitConstructionObject(param, valueInputs, objectInputs);
                    toolbarLayout.first(toolbar);
                }
            });
            JButton cancelButton = new JButton("Zpět");
                cancelButton.addActionListener(new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        toolbarLayout.first(toolbar);
                    }
                });
            first.add(cancelButton);
            first.add(okButton);
            panel.add(first, "Vyberte");
            return panel;
        }
    }

    /**
     * Prida do panelu vsechny pole dane argumentem params.
     * Vsechny hodnotove da do pole valueInputs, vsechny objektove da do pole objectInputs.
     * @param panel Panel, do ktereho se budou pridavat vstupni pole.
     * @param params parametry, ktere se budou pridavat.
     * @param valueInputs list, do ktereho se budou ukladat odkazy na vsechny JTextField pro hodnotove parametry
     * @param objectInputs list, do ktereho se budou ukladat odkazy na vsechny objectInputs
     */
    private void addParameterInputs(JPanel panel, InputParametersInterface params, List<JTextField> valueInputs, List<JTextField> objectInputs){
        for(ParameterItem item: params.getParameters()){
                    if(item instanceof ParameterString){
                        panel.add(new JLabel(((ParameterString) item).getText()));
                    }
                    if(item instanceof ParameterValue){
                        ParameterValue t = (ParameterValue) item;
                        PlaceholderField field = new PlaceholderField(5);
                        field.setPlaceholder(t.getCaption());
                        valueInputs.add(field);
                        panel.add(field);
                    }
                    if(item instanceof ParameterObject){
                        ParameterObject o = (ParameterObject) item;
                        PlaceholderField field = new PlaceholderField(5);
                        field.setPlaceholder(o.getCaption());
                        objectInputs.add(field);
                        panel.add(field);
                    }
                }
    }

    private void submitConstructionObject(InputParametersInterface params, List<JTextField> valueInputs, List<JTextField> objectInputs){
        String[] objectArguments = new String[objectInputs.size()];
        ValueArgument[] valueArguments = new ValueArgument[valueInputs.size()];
        int i = 0;
        for(JTextField field: objectInputs){
            objectArguments[i++] = field.getText();
            field.setText("");
        }
        i = 0;
        for(JTextField field: valueInputs){
            DefaultValueArgument arg = new DefaultValueArgument();
            // WARNING: neplním valueArgumenty jejich jmény. Snad je nebudu potřebovat.
            arg.setRealInput(field.getText());
            field.setText("");
            valueArguments[i++] = arg;
        }
        ConstructObjectEvent e = new ConstructObjectEvent(name, params.getParametersCaption(), valueArguments, objectArguments);
        this.fireConstructionObjectEvent(e);
    }

    private class ComboBoxSelectedListener implements ActionListener{
        private ComboBoxModel<String> model;
        private CardLayout cardLayout;
        private Container layoutComponent;

        public ComboBoxSelectedListener(ComboBoxModel<String> model, CardLayout cardLayout, Container layoutComponent) {
            this.model = model;
            this.cardLayout = cardLayout;
            this.layoutComponent = layoutComponent;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            String selected = model.getSelectedItem().toString();
            cardLayout.show(layoutComponent, selected);
        }

    }

}